package com.gframework.paramparse.core.extension;

import java.util.Map;
import java.util.Optional;

import org.springframework.lang.Nullable;

/**
 * 自定义扩展参数获取接口实现抽象类.
 * 继承此类只需要复写 {@link #getValue(String)} 一个方法即可。
 * 
 * @since 1.0.0
 * @author Ghwolf
 * 
 * @see ExtParam
 * @see HashMapExtParam
 */
public abstract class ExtParamContext implements ExtParam {

	/**
	 * 空的extParam接口对象
	 */
	private static final ExtParam EMPTY_EXT_PARAM = new ExtParam() {

		@Override
		public <T> Optional<T> get(String key, Class<T> valueType) throws ExtParamNotFoundException {
			return Optional.empty();
		}

		@Override
		public <T> T getNotNull(String key, Class<T> valueType) throws ExtParamNotFoundException {
			throw ExtParamNotFoundException.non(key);
		}

		@Override
		public <T> T get(String key, Class<T> valueType, T defaultValue) {
			return defaultValue;
		}
	};

	@SuppressWarnings("unchecked")
	@Override
	public <T> Optional<T> get(String key, Class<T> valueType) throws ExtParamNotFoundException {
		Object value = this.getValue(key);
		if (value == null) return Optional.empty();
		if (!valueType.isAssignableFrom(value.getClass())) {
			throw ExtParamNotFoundException.typeError(key, valueType, value.getClass());
		}
		return (Optional<T>) Optional.of(value);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T getNotNull(String key, Class<T> valueType) throws ExtParamNotFoundException {
		Object value = this.getValue(key);
		if (value == null) {
			throw ExtParamNotFoundException.non(key);
		}
		if (!valueType.isAssignableFrom(value.getClass())) {
			throw ExtParamNotFoundException.typeError(key, valueType, value.getClass());
		}
		return (T) value;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T get(String key, Class<T> valueType, T defaultValue) {
		Object value = this.getValue(key);
		if (value == null) return defaultValue;
		if (!valueType.isAssignableFrom(value.getClass())) return defaultValue;
		return (T) value;
	}

	/**
	 * 取得一个空的ExtParam接口对象.
	 * 这是一个全局唯一的，不会获取到任何参数的，也无法扩展的空的扩展参数获取对象
	 * 
	 * @return 返回空的扩展参数获取对象
	 */
	public static ExtParam getEmptyExtParam() {
		return EMPTY_EXT_PARAM;
	}

	/**
	 * 返回一个只有一个参数对的extParam接口对象
	 * 
	 * @param key 参数key
	 * @param value 参数值
	 * @return 返回仅包含一个参数的extParam接口对象
	 */
	public static ExtParam getSingleExtParam(String key, Object value) {
		return new SingleExtParam(key, value);
	}

	/**
	 * 返回一个基于Map存储的多自定义扩展参数操作对象
	 * 
	 * @param m 参数{@code key-value}对
	 * @return 返回仅包含一个参数的extParam接口对象
	 */
	public static HashMapExtParam getMapExtParam(Map<? extends String, ? extends Object> m) {
		return new HashMapExtParam(m);
	}

	/**
	 * 返回一个基于Map存储的多自定义扩展参数操作对象
	 * 
	 * @param initialCapacity map长度
	 * @return 返回仅包含一个参数的extParam接口对象
	 */
	public static HashMapExtParam getMapExtParam(int initialCapacity) {
		return new HashMapExtParam(initialCapacity);
	}

	/**
	 * 返回一个基于Map存储的多自定义扩展参数操作对象
	 * 
	 * @return 返回仅包含一个参数的extParam接口对象
	 */
	public static HashMapExtParam getMapExtParam() {
		return new HashMapExtParam();
	}

	/**
	 * 根据key取得参数值
	 * 
	 * @param key 参数key
	 * @return 返回参数值，允许为null
	 */
	@Nullable
	protected abstract Object getValue(String key);

}
